#include <SPI.h>
#include <avr/io.h>

#define VERSION         "1.0"
#define IDENT           "EEPROM28NEW"

#define Unsupport       "Unsupport"

//数据
#define Data0 PIN_PC0
#define Data1 PIN_PC1
#define Data2 PIN_PD2
#define Data3 PIN_PD3
#define Data4 PIN_PD4
#define Data5 PIN_PD5
#define Data6 PIN_PD6
#define Data7 PIN_PD7

//595控制
//#define DATA595    PIN_PB3 //数据位
#define LATCH PIN_PB2
#define SCK   PIN_PB5

#define chipCE PIN_PB1
#define chipOE PIN_PC5

//电压控制
#define V_OE   PIN_PC2   //OE
#define V_A9   PIN_PC3   //A9
#define V_A15  PIN_PC4   //A15

#define A_14  PIN_PB0   //A14

#define P_A6 PIN_A6

// Buffers
#define BUFF_LEN 64

uint8_t pageBuffer[BUFF_LEN];                  // page buffer
char    cmdBuffer[22];                         // command buffer

void read_mode(void){
  pinMode(Data0, INPUT_PULLUP);
  pinMode(Data1, INPUT_PULLUP);
  pinMode(Data2, INPUT_PULLUP);
  pinMode(Data3, INPUT_PULLUP);
  pinMode(Data4, INPUT_PULLUP);
  pinMode(Data5, INPUT_PULLUP);
  pinMode(Data6, INPUT_PULLUP);
  pinMode(Data7, INPUT_PULLUP);
//  PINC &= 0b00000011;
//  PIND &= 0b11111100;
}

void write_mode(void){
  pinMode(Data0, OUTPUT);
  pinMode(Data1, OUTPUT);
  pinMode(Data2, OUTPUT);
  pinMode(Data3, OUTPUT);
  pinMode(Data4, OUTPUT);
  pinMode(Data5, OUTPUT);
  pinMode(Data6, OUTPUT);
  pinMode(Data7, OUTPUT);
//  DDRC |= 0b00000011;
//  DDRD |= 0b11111100;
}


byte read_data_bus(void){
//  return ((digitalRead(Data7) << 7) +
//          (digitalRead(Data6) << 6) +
//          (digitalRead(Data5) << 5) +
//          (digitalRead(Data4) << 4) +
//          (digitalRead(Data3) << 3) +
//          (digitalRead(Data2) << 2) +
//          (digitalRead(Data1) << 1) +
//          digitalRead(Data0));
  return (PINC & 0b00000011) | (PIND & 0b11111100);
}

void write_data_bus(byte data){
  digitalWrite(Data0, data & 1);
  digitalWrite(Data1, (data>>1) & 1);
  digitalWrite(Data2, (data>>2) & 1);
  digitalWrite(Data3, (data>>3) & 1);
  digitalWrite(Data4, (data>>4) & 1);
  digitalWrite(Data5, (data>>5) & 1);
  digitalWrite(Data6, (data>>6) & 1);
  digitalWrite(Data7, (data>>7) & 1);
}

void setup() {
  //初始化
  pinMode(P_A6, INPUT);//ADC6
//  pinMode(DATA595, OUTPUT);
  pinMode(SCK, OUTPUT);
  pinMode(LATCH, OUTPUT);
//  digitalWrite(DATA595, LOW);
  digitalWrite(SCK, LOW);
  digitalWrite(LATCH, LOW);

  // SPI
//  SPCR = (1<<SPE) | (1<<MSTR);                // start SPI as Master
//  SPSR = (1<<SPI2X);                          // set speed to F_CPU/2
  SPI.begin();

  //地址线14
  pinMode(A_14, OUTPUT);
  digitalWrite(A_14,LOW);


  pinMode(chipCE, OUTPUT);
  pinMode(chipOE, OUTPUT);
  digitalWrite(chipCE,HIGH);
  digitalWrite(chipOE,HIGH);

  pinMode(V_OE,OUTPUT);
  pinMode(V_A9,OUTPUT);
  pinMode(V_A15,OUTPUT);
  digitalWrite(V_OE,LOW);
  digitalWrite(V_A9,LOW);
  digitalWrite(V_A15,LOW);

  read_mode();
  // 初始化地址
//  setAddress(0,28256);

//  Serial.begin(1000000);
  Serial.begin(115200);
}

const uint8_t chip_size = 6;
const uint32_t chips[chip_size] = {
  2764,
  27128,
  27256,
  27512,
  2864,
  28256
};

//是否支持
boolean chipSupport(uint32_t chipId){
  for(int i=0;i<chip_size;i++){
    if(chips[i]==chipId)return true;
  }
  return false;
}

void check(uint32_t chipId){
//  if(chipSupport(chipId)){
    Serial.println(F("ok"));
//  }else{
//    Serial.println(F("Unsupport"));
//  }
}

void loop() {
  //程序判断用
  Serial.println("Ready");
  //r  28256  0000  ffff
  //0 2+6     10    16
  readCommand();
  char cmd = cmdBuffer[0];                      //指令
  uint32_t chipId    = hexChip(cmdBuffer+2);    //芯片
  uint32_t startAddr = hexWord(cmdBuffer+10);   //开始地址
  uint32_t endAddr   = hexWord(cmdBuffer+16);   //结束地址

  if (endAddr < startAddr) endAddr = startAddr;
  // 数据长度
  uint32_t dataLength = endAddr - startAddr + 1;

  if(chipId>0 && !chipSupport(chipId)){
    Serial.println(Unsupport);
    return;
  }

  switch(cmd) {
    case 'i':   Serial.println(IDENT); break;
    case 'v':   Serial.println(VERSION); break;
    case 'a':   Serial.println(get_voltage());break;
    case 'c':   check(chipId); break;

    case 's':   read27Sid(chipId); break;
    case 'e':   eraser(chipId);break;

    case 'r':   readBinary(startAddr, dataLength,chipId);
                break;
    case 'w':
                if(chipId==2764||chipId==27128||chipId==27256||chipId==27512){
                  write27(startAddr,dataLength,chipId);
                }else{
                  Serial.print(F("Write "));
                  Serial.println(Unsupport);
                }
                break;

//    case 'x':
//                Serial.println(cmdBuffer);
//                Serial.print(chipId);Serial.print(" ");
//                Serial.print(startAddr);Serial.print(" ");
//                Serial.print(endAddr);Serial.print(" ");
//                Serial.print(dataLength);Serial.print(" ");
//                Serial.print(chipId);Serial.print(" ");
//                Serial.println("");
//                break;
    case 'z': 
                digitalWrite(V_OE,HIGH);
                digitalWrite(V_A9,HIGH);
                digitalWrite(V_A15,HIGH);
                break;
    default:    break;
  }
}

void setAddress(uint32_t addr,uint32_t chipId) {

  //处理VPP
  if(chipId==2764||chipId==27128||chipId==27256){
    addr |= 0x8000;
  }

  // A14地址线
  if(chipId==27256||chipId==27512){
    digitalWrite(A_14,(addr>>14)&1);
  }

  // SPI
//  SPDR = highByte(addr);                      // high byte of address
//  while (!(SPSR & (1<<SPIF)));                // wait for SPI process to finish
//  SPDR = lowByte(addr);                       // low byte of address
//  while (!(SPSR & (1<<SPIF)));                // wait for SPI process to finish

  SPI.transfer16(addr);

  digitalWrite(LATCH, HIGH);
  digitalWrite(LATCH, LOW);
}

// 读取芯片内容(读取的时候ce oe全部拉低，改变地址就可以输出)
void readBinary(uint32_t addr, uint32_t count,uint32_t chipId) {
  read_mode();
  
  digitalWrite(chipCE, LOW);
  while (count) {
    Serial.write(readByte(addr++, chipId));
    count--;
  }
  digitalWrite(chipCE, HIGH);
}
// 根据地址读取数据
uint8_t readByte(uint32_t addr,uint32_t chipId){
  setAddress (addr,chipId);
  digitalWrite(chipOE, LOW);
  delayMicroseconds(7);
  uint8_t b = read_data_bus();
  digitalWrite(chipOE, HIGH);
  return b;
}


// 擦除
void eraser(uint32_t chipId){
  // 写模式 写0
  write_mode();
  write_data_bus(0xff);
  delayMicroseconds(5);


    if(chipId==27512){
        setAddress (0x200,chipId);
        digitalWrite(V_A9,HIGH);
        digitalWrite(V_OE,HIGH);

        delayMicroseconds(1);
        digitalWrite(chipCE,LOW);
        delay(105);
        digitalWrite(chipCE,HIGH);
        delayMicroseconds(10);
    }else if(chipId==27256){
        setAddress (0x200,chipId);
        digitalWrite(V_A9,HIGH);
        digitalWrite(V_A15,HIGH);

        delayMicroseconds(1);
        digitalWrite(chipCE,LOW);
        delay(105);
        digitalWrite(chipCE,HIGH);
        delayMicroseconds(10);

    // 这个容量应该没有电擦除的片
    }else if(chipId==27128||chipId==2764){
        //PGM=1
        digitalWrite(A_14,HIGH);
        digitalWrite(chipCE,LOW);

        delayMicroseconds(1);
        //PGM=0
        digitalWrite(A_14,LOW);
        delay(105);
        digitalWrite(A_14,HIGH);
        delayMicroseconds(10);

        digitalWrite(chipCE,HIGH);
        delayMicroseconds(10);
    }

  digitalWrite(chipOE,LOW);
  digitalWrite(V_A15,LOW);
  digitalWrite(V_OE,LOW);
  digitalWrite(V_A9,LOW);
  setAddress (0,chipId);
  delay(10);
  read_mode();
  digitalWrite(chipOE,HIGH);

}

// 读取芯片信息
void read27Sid(uint32_t chipId){
  read_mode();
  digitalWrite(chipCE,LOW);
  setAddress(0,chipId);
  digitalWrite(V_A9,HIGH);
  digitalWrite(chipOE,LOW);
  delayMicroseconds(10);
  Serial.write(read_data_bus());//输出
  digitalWrite(chipOE,HIGH);
  
  setAddress(1,chipId);
  digitalWrite(chipOE,LOW);
  delayMicroseconds(10);
  Serial.write(read_data_bus());//输出
  
  digitalWrite(chipOE,HIGH);
  digitalWrite(chipCE,HIGH);
  digitalWrite(V_A9,LOW);
}

// 写入
void write27(uint32_t addr, uint32_t count, uint32_t chipId){
  for (uint8_t i=0; i<BUFF_LEN; i++) {
    while (!Serial.available());
    pageBuffer[i] = Serial.read();
  }

  write_mode();
  delayMicroseconds(10);

  if(chipId==2764||chipId==27128||chipId==27256){
    // A15 VPP=12V
    digitalWrite(V_A15,HIGH);
    digitalWrite(chipOE,HIGH);
    //PGM=0 写入
    if(chipId==2764||chipId==27128){
      digitalWrite(A_14,HIGH);
      digitalWrite(chipCE,LOW);
    }
  }
  // 27c512
  if(chipId==27512){
    digitalWrite(V_OE,HIGH);
    digitalWrite(chipOE,HIGH);
  }

  delayMicroseconds(15);
  for(uint8_t i=0; i<BUFF_LEN; i++){
    write_byte27(addr+i,pageBuffer[i],chipId);
    delayMicroseconds(10);
  }

  digitalWrite(V_OE,LOW);
  digitalWrite(V_A15,LOW);

  digitalWrite(chipCE,HIGH);
  digitalWrite(chipOE,HIGH);

  check_buff(addr,chipId);
}

void check_buff(uint32_t addr, uint32_t chipId){
  int i;
  uint8_t rd;
  
  read_mode();
  if(chipId==2864||chipId==28256){
    digitalWrite(A_14, HIGH);
    delay(50);
  }
  //读数据校验
  digitalWrite(chipCE, LOW);
  delayMicroseconds(10);
//  boolean has_error = false;
  for(i=0;i<BUFF_LEN ;i++){
    rd = readByte(addr+i,chipId);
    if(pageBuffer[i]!=rd){
      Serial.print("0x");
      Serial.print(addr+i,HEX);
      Serial.print("=");
      Serial.print(rd,HEX);
      Serial.print(",");
      Serial.print(pageBuffer[i],HEX);
      Serial.println(" ");
//      has_error = true;
      break;
    }
  }
//  if(has_error){
//    Serial.print("chipId:");
//    Serial.println(chipId);
//  }
  digitalWrite(chipCE, HIGH);

}

// 写入byte，需要OE高，改变CE写入数据
void write_byte27(uint32_t address, byte data,uint32_t chipId) {
  //如果是0xff直接返回
  if(data==0xff)return;
  write_data_bus(data);
  setAddress(address,chipId);
  delayMicroseconds(20);

  // 2764和27128通过PGM变化写入数据
  if(chipId==2764||chipId==27128){
    digitalWrite(A_14, LOW);
    //ST-27手册标注这里需要2.85-78.75毫秒时间写入
    delay(5);
    digitalWrite(A_14, HIGH);
  // 27256和27512通过ce变化写入数据
  }else if(chipId==27256||chipId==27512){
    digitalWrite(chipCE, LOW);
    delayMicroseconds(105);
    digitalWrite(chipCE, HIGH);
  }
}

float get_voltage (void) {
  float v_ADC = (analogRead(P_A6) / 1024.) * 5.;
  return (v_ADC / 2000.0 * (10000.0 + 2000.0));
}

void readCommand() {
  for(uint8_t i=0; i< 22; i++) cmdBuffer[i] = 0;  // clear command buffer
  char c; uint8_t idx = 0;                        // initialize variables
  do {
    if(Serial.available()) {
      c = Serial.read();
      cmdBuffer[idx++] = c;
    }
  } while (c != '\n' && idx < 22);
  cmdBuffer[idx - 1] = 0;                     // change last newline to '\0' termination
}


// converts character representing a hex nibble into 4-bit value
uint8_t hexDigit(char c) {
  if      (c >= '0' && c <= '9') return c - '0';
  else if (c >= 'a' && c <= 'f') return c - 'a' + 10;
  else if (c >= 'A' && c <= 'F') return c - 'A' + 10;
  else return 0;
}

byte hexByte(char* a) {
  return ((hexDigit(a[0])*16) + hexDigit(a[1]));
}


// 返回字芯片字符串
uint32_t hexChip(char* data){
    uint32_t re = 0;
//    if(data[0]>=0x30 && data[0]<=0x39)re+=(data[0]-0x30)*100000;
    if(data[1]>=0x30 && data[1]<=0x39)re+=(data[1]-0x30)*10000;
    if(data[2]>=0x30 && data[2]<=0x39)re+=(data[2]-0x30)*1000;
    if(data[3]>=0x30 && data[3]<=0x39)re+=(data[3]-0x30)*100;
    if(data[4]>=0x30 && data[4]<=0x39)re+=(data[4]-0x30)*10;
    if(data[5]>=0x30 && data[5]<=0x39)re+=(data[5]-0x30)*1;
    return re;
}

// converts string containing a hex word into 16-bit value
uint16_t hexWord(char* data) {
  return (
    (hexDigit(data[0])*4096)+
    (hexDigit(data[1])*256)+
    (hexDigit(data[2])*16)+
    (hexDigit(data[3])));
}
